﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using X.Infrastructure.Shapes;
using X.Infrastructure.WPF.Extends;
using X.WPF.Controls.Enums;
using X.WPF.Controls.EventArgs.CanvasShapeArgs;
using X.WPF.Controls.EventArgs.DraggableControlArgs;
using Panel = System.Windows.Controls.Panel;

namespace X.WPF.Controls.CustomControls
{
    /// <summary>
    /// 画布多线段控件
    /// </summary>
    public class CanvasPolyline : CanvasShape
    {
        #region # 字段及构造器

        /// <summary>
        /// 点位控件列表
        /// </summary>
        private readonly ObservableCollection<Ellipse> _pointElements;

        /// <summary>
        /// 是否绘制
        /// </summary>
        private bool _isDraw;

        /// <summary>
        /// 静态构造器
        /// </summary>
        static CanvasPolyline()
        {
            CanvasPolyline.PointsProperty = DependencyProperty.Register(nameof(CanvasPolyline.Points), typeof(ObservableCollection<PointX>), typeof(CanvasPolyline), new PropertyMetadata(new ObservableCollection<PointX>(), CanvasPolyline.OnPointsChanged));
        }

        /// <summary>
        /// 默认构造器
        /// </summary>
        public CanvasPolyline()
            : base(CanvasShapeType.Polyline)
        {
            this._pointElements = new ObservableCollection<Ellipse>();
            this.Points = new ObservableCollection<PointX>();


            // 绑定填充颜色
            Binding fillBinding = new Binding(nameof(this.Fill))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            this.ShapeElement.SetBinding(Shape.FillProperty, fillBinding);
        }

        #endregion

        #region # 属性

        #region 点位列表 —— ObservableCollection<PointX> Points

        /// <summary>
        /// 点位列表依赖属性
        /// </summary>
        public static DependencyProperty PointsProperty;

        /// <summary>
        /// 点位列表
        /// </summary>
        public ObservableCollection<PointX> Points
        {
            get => (ObservableCollection<PointX>)base.GetValue(CanvasPolyline.PointsProperty);
            set => base.SetValue(CanvasPolyline.PointsProperty, value);
        }

        #endregion

        #endregion

        #region # 依赖属性 

        #endregion

        #region # 回调方法

        #region 点位列表改变回调方法 —— static void OnPointsChanged(DependencyObject dependencyObject...
        /// <summary>
        /// 点位列表改变回调方法
        /// </summary>
        private static void OnPointsChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            CanvasPolyline canvasPolyline = (CanvasPolyline)dependencyObject;

        }
        #endregion 

        #endregion

        #region # 路由事件

        #endregion

        #region # 事件处理程序

        #region 画布鼠标左键按下事件 —— void OnCanvasMouseLeftButtonDown(object sender...
        /// <summary>
        /// 画布鼠标左键按下事件
        /// </summary>
        private void OnCanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
        {
            if (this._parentCanvas == null)
                return;

            PointX position = eventArgs.GetPosition(this._parentCanvas).ToPointX();
            this.PointRender(position);
        }
        #endregion

        #region 画布鼠标右键按下事件 —— void OnCanvasMouseRightButtonDown(object sender...
        /// <summary>
        /// 画布鼠标右键按下事件
        /// </summary>
        private void OnCanvasMouseRightButtonDown(object sender, MouseButtonEventArgs eventArgs)
        {
            this._isDraw = false;
            if (this._parentCanvas == null)
                return;

            bool result = this.PolylineRender();

            this._parentCanvas.MouseLeftButtonDown -= this.OnCanvasMouseLeftButtonDown;
            this._parentCanvas.MouseRightButtonDown -= this.OnCanvasMouseRightButtonDown;
            if (result)
            {
                CanvasShapeElementDrawnEventArgs areArgs = new CanvasShapeElementDrawnEventArgs(CanvasShape._ShapeDrawnEvent, this, this);
                this.RaiseEvent(areArgs);

                if (!areArgs.IsCancel)
                    return;

                this.DrawCancel();
            }
            else
            {
                this._parentCanvas.Children.Remove(this);
                this.RaiseEvent(new CanvasShapeElementDrawCancelEventArgs(CanvasShape._ShapeDrawCancelEvent, this, this));
            }
        }
        #endregion

        #region 多线段鼠标按下事件 —— void OnCircleMouseDown(object sender, MouseEventArgs eventArgs)
        /// <summary>
        /// 多线段鼠标按下事件
        /// </summary>
        private void OnCircleMouseDown(object sender, MouseEventArgs eventArgs)
        {
            // 挂起路由事件
            this.RaiseEvent(new CanvasShapeElementClickEventArgs(CanvasShape._ShapeClickEvent, this, null, this));
        }
        #endregion

        #endregion

        #region # 方法

        // Override

        #region 绘制 —— override void Draw(PointX startPoint)
        /// <summary>
        /// 绘制
        /// </summary>
        /// <param name="startPoint">起点</param>
        public override void Draw(PointX startPoint)
        {
            if (this._parentCanvas == null)
                return;

            this._parentCanvas.MouseLeftButtonDown += this.OnCanvasMouseLeftButtonDown;
            this._parentCanvas.MouseRightButtonDown += this.OnCanvasMouseRightButtonDown;
            this._isDraw = true;

            this.PointRender(startPoint);
        }
        #endregion

        #region 绘制 —— override void Draw(double scale, ShapeX shapeX)
        /// <summary>
        /// 绘制
        /// </summary>
        public override void Draw(double scale, ShapeX shapeX)
        {
            PolylineX polylineX = (PolylineX)shapeX;

            IEnumerable<PointX> points = polylineX.Points.Select(i =>
            {
                double x = i.X * scale;
                double y = i.Y * scale;
                PointX point = new PointX(x, y);

                this.PointRender(point);

                return point;
            });

            this.Points = new ObservableCollection<PointX>(points);
            this.Name = polylineX.Name;
            this.Tag = polylineX.Tag;

            this.PolylineRender();
        }
        #endregion

        #region 绘制取消 —— abstract void DrawCancel()
        /// <summary>
        /// 绘制取消
        /// </summary> 
        public override void DrawCancel()
        {
            foreach (Ellipse pointElement in this._pointElements)
            {
                this._parentCanvas?.Children.Remove(pointElement);
            }

            base.DrawCancel();
        }
        #endregion

        #region 拖拽 —— override void Drag(DraggedEventArgs draggedEventArgs)
        /// <summary>
        /// 拖拽
        /// </summary> 
        /// <param name="draggedEventArgs">拖拽参数</param>
        public override void Drag(DraggedEventArgs draggedEventArgs)
        {
        }
        #endregion

        #region 初始化形状控件 —— void InitShapeElement()
        /// <summary>
        /// 初始化形状控件
        /// </summary>
        protected override Shape InitShapeElement()
        {
            Polyline polyline = new Polyline();
            polyline.MouseDown += this.OnCircleMouseDown;

            return polyline;
        }
        #endregion


        // Private 

        #region 渲染点 —— void PointRender(PointX position)
        /// <summary>
        /// 渲染点
        /// </summary>
        /// <param name="position">位置</param>
        private void PointRender(PointX position)
        {
            int radius = 3;

            Brush colorBrush = this.Stroke;
            if (this._isDraw && this._pointElements.Count == 0)
            {
                colorBrush = new SolidColorBrush(Colors.Yellow);
            }

            Ellipse pointElement = new Ellipse
            {
                Width = radius * 2,
                Height = radius * 2,
                StrokeThickness = 1,
                Fill = colorBrush,
                Stroke = colorBrush
            };
            Canvas.SetLeft(pointElement, position.X - radius);
            Canvas.SetTop(pointElement, position.Y - radius);
            Panel.SetZIndex(pointElement, this.ZIndex - 1);

            this._pointElements.Add(pointElement);
            this._parentCanvas.Children.Add(pointElement);

            this.Points.Add(position);
        }
        #endregion

        #region 渲染点位列表 —— void PointsRender()
        /// <summary>
        /// 渲染点位列表
        /// </summary>
        private void PointsRender()
        {

            foreach (Ellipse pointElement in this._pointElements)
            {
                // 绑定画笔
                Binding strokeBinding = new Binding(nameof(this.Stroke))
                {
                    Source = this,
                    Mode = BindingMode.TwoWay
                };
                pointElement.SetBinding(Shape.StrokeProperty, strokeBinding);
                pointElement.SetValue(Shape.StrokeProperty, this.Stroke);

                // 绑定画笔粗细
                Binding strokeThicknessBinding = new Binding(nameof(this.StrokeThickness))
                {
                    Source = this,
                    Mode = BindingMode.TwoWay
                };
                pointElement.SetBinding(Shape.StrokeThicknessProperty, strokeThicknessBinding);
                pointElement.SetValue(Shape.StrokeThicknessProperty, this.StrokeThickness);

                // 绑定填充颜色
                Binding fillBinding = new Binding(nameof(this.Fill))
                {
                    Source = this,
                    Mode = BindingMode.TwoWay
                };
                pointElement.SetBinding(Shape.FillProperty, fillBinding);
                pointElement.SetValue(Shape.FillProperty, this.Fill);
            }
        }
        #endregion

        #region 渲染多线段 —— bool PolylineRender()
        /// <summary>
        /// 渲染多线段
        /// </summary>
        private bool PolylineRender()
        {
            if (this.Points.Count < 2)
                return false;

            if (!this._parentCanvas.Children.Contains(this.ShapeElement))
                this._parentCanvas.Children.Add(this.ShapeElement);

            // 绘制点
            PointCollection points = new PointCollection();
            foreach (PointX polyPoint in this.Points)
            {
                Point point = polyPoint.ToPoint();
                points.Add(point);
            }

            // 绘制多线段
            this.ShapeElement.SetValue(Polyline.PointsProperty, points);
            Panel.SetZIndex(this.ShapeElement, this.ZIndex);

            // 渲染点位列表
            this.PointsRender();

            return true;
        }
        #endregion

        #endregion
    }
}